#include "stdafx.h"
#include "TestSuiteTool.h"
#include "AddIn.h"
#include "Connect.h"
#include "atlsafe.h"
#include "CreatePrjDlgImpl.h"

using namespace VCProjectEngineLibrary;

CTestSuiteTool::CTestSuiteTool(CConnect* pParent)
:m_pParent(pParent)
{
}

CTestSuiteTool::~CTestSuiteTool(void)
{
	RestoreChangedProject();

	TCHAR szIDEPath[MAX_PATH] = {0};
	GetModuleFileName(NULL, szIDEPath, MAX_PATH);
	CString szToolPath = MergePath(szIDEPath, _T("..\\..\\Team Tools\\Performance Tools"));

	CString szStop(szToolPath);
	szStop += L"\\VSPerfCmd.exe /SHUTDOWN";
	m_PerformStop.Exec(szStop);
	m_PerformStop.Join(INFINITE);
	m_PerformMon.Join(INFINITE);
}

int CTestSuiteTool::HandleCommand(int nCmd)
{
	if(m_pParent == NULL)
		return -1;

	switch(nCmd)
	{
	case Command_CreateTestProject:
		m_pParent->PrintToOutput(_T("Create new test project."), TRUE);
		CreateProjectFromTemplate();
		break;
	case Command_RunTestProject:
		RunSolutionWithCoverage(FALSE);
		m_pParent->PrintToOutput(_T("Run all test cases."), TRUE);
		break;
	case Command_AutoMock:
		StopCoverage();
		m_pParent->PrintToOutput(_T("Generate mock class based on current interface."), TRUE);
		break;
	default:
		break;
	}

	return 0;
}

void CTestSuiteTool::GetConfigure(LPCTSTR szName, IVCCollection* manager, VCConfiguration** cfg)
{
	if(manager == NULL || cfg == NULL)
		return;

	long lBasePropsCnt = 0;

	manager->get_Count(&lBasePropsCnt);
	int i = 0;
	for(i = 1; i <= lBasePropsCnt; i++)
	{
		CComPtr<IDispatch> pObj;
		CComQIPtr<VCConfiguration> cfgTmp;
		manager->Item(CComVariant(i), &pObj);
		cfgTmp = pObj;
		if(cfgTmp == NULL)
			continue;

		BSTR sCfgName = NULL;
		cfgTmp->get_ConfigurationName(&sCfgName);
		CString strCfgName;
		strCfgName = sCfgName;
		strCfgName.MakeLower();
		SysFreeString(sCfgName);
		if(strCfgName.Find(szName) >= 0)
		{
			*cfg = cfgTmp;
			(*cfg)->AddRef();
			break;
		}
	}
}

void CTestSuiteTool::AlignRelPath(BSTR& bstrInput, LPCWSTR sOrig, LPCWSTR sDest)
{
	CString sInput;
	sInput = bstrInput;
	sInput = MergePath(sOrig, sInput);
	CString sRet;
	sRet = GetRelPath(sDest, sInput);
	SysFreeString(bstrInput);
	bstrInput = sRet.AllocSysString();
}

void CTestSuiteTool::MergeMacroDef(BSTR& bstrMacro)
{
	CString sRet(_T("WIN32;_CONSOLE"));
	CString sMacro(bstrMacro);

	CString resToken;
	int curPos = 0;
	resToken= sMacro.Tokenize(_T("; "), curPos);
	while(resToken != _T(""))
	{
		if(resToken != _T("_USRDLL") && resToken.Find(_T("_EXPORTS")) < 0)
		{
			sRet += _T(";");
			sRet += resToken;
		}
		resToken = sMacro.Tokenize(_T("; "), curPos);
	}

	SysFreeString(bstrMacro);
	bstrMacro = sRet.AllocSysString();
}

void CTestSuiteTool::AlignRelPathEx(BSTR& bstrInput, LPCWSTR sOrig, LPCWSTR sDest, int nType)
{
	CString sRet;
	CString sMacro(bstrInput);

	CString resToken;
	int curPos = 0;
	resToken= sMacro.Tokenize(_T("; "), curPos);
	while(resToken != _T(""))
	{
		if(resToken.GetAt(0) != _T('.') && nType == 3)
		{
			sRet += resToken;
			sRet += _T(" ");
		}
		else
		{
			CString strTmp = MergePath(sOrig, resToken);
			strTmp = GetRelPath(sDest, strTmp);
			sRet += strTmp;
			if(nType == 3)
				sRet += _T(" ");
			else
				sRet += _T(";");
		}
		resToken = sMacro.Tokenize(_T("; "), curPos);
	}
	if(nType == 1)
	{
		CString strTmp = MergePath(sOrig, _T(".\\"));
		strTmp = GetRelPath(sDest, strTmp);
		sRet += strTmp;
		sRet += _T(";");

		TCHAR szTemplatePath[MAX_PATH] = {0};
		GetModuleFileName(_AtlModule.GetResourceInstance(), szTemplatePath, MAX_PATH);
		PathRemoveFileSpec(szTemplatePath);
		PathAppend(szTemplatePath, _T("gmock\\include"));
		sRet += szTemplatePath;
	}
	else if(nType == 2)
	{
		TCHAR szTemplatePath[MAX_PATH] = {0};
		GetModuleFileName(_AtlModule.GetResourceInstance(), szTemplatePath, MAX_PATH);
		PathRemoveFileSpec(szTemplatePath);
		PathAppend(szTemplatePath, _T("gmock\\libs"));
		sRet += szTemplatePath;
	}

	SysFreeString(bstrInput);
	bstrInput = sRet.AllocSysString();
}

void CTestSuiteTool::CopyConfig(VCConfiguration* baseCfg, BSTR bstrBasePath, VCConfiguration* newCfg, BSTR bstrNewPath)
{
	if(baseCfg == NULL || newCfg == NULL)
		return;

	BSTR bstrTmp = NULL;
	baseCfg->get_OutputDirectory(&bstrTmp);
	AlignRelPath(bstrTmp, bstrBasePath, bstrNewPath);
	newCfg->put_OutputDirectory(bstrTmp);
	SysFreeString(bstrTmp);
	bstrTmp = NULL;

	baseCfg->get_IntermediateDirectory(&bstrTmp);
	AlignRelPath(bstrTmp, bstrBasePath, bstrNewPath);
	newCfg->put_IntermediateDirectory(bstrTmp);
	SysFreeString(bstrTmp);
	bstrTmp = NULL;

	charSet aChSet;
	baseCfg->get_CharacterSet(&aChSet);
	newCfg->put_CharacterSet(aChSet);

	CComQIPtr<VCCLCompilerTool> ccBaseTool;
	CComQIPtr<VCCLCompilerTool> ccNewTool;
	CComQIPtr<VCLinkerTool> lnkBaseTool;
	CComQIPtr<VCLinkerTool> lnkNewTool;

	CComPtr<IDispatch> pObj;
	baseCfg->get_Tools(&pObj);
	CComQIPtr<IVCCollection> pTools;
	pTools = pObj;
	pObj = NULL;
	pTools->Item(CComVariant("VCCLCompilerTool"), &pObj);
	ccBaseTool = pObj;
	pObj = NULL;
	pTools->Item(CComVariant("VCLinkerTool"), &pObj);
	lnkBaseTool = pObj;

	pObj = NULL;
	newCfg->get_Tools(&pObj);
	pTools = pObj;
	pObj = NULL;
	pTools->Item(CComVariant("VCCLCompilerTool"), &pObj);
	ccNewTool = pObj;
	pObj = NULL;
	pTools->Item(CComVariant("VCLinkerTool"), &pObj);
	lnkNewTool = pObj;

	ccBaseTool->get_PreprocessorDefinitions(&bstrTmp);
	MergeMacroDef(bstrTmp);
	ccNewTool->put_PreprocessorDefinitions(bstrTmp);
	SysFreeString(bstrTmp);
	bstrTmp = NULL;

	ccBaseTool->get_AdditionalIncludeDirectories(&bstrTmp);
	AlignRelPathEx(bstrTmp, bstrBasePath, bstrNewPath,1);
	ccNewTool->put_AdditionalIncludeDirectories(bstrTmp);
	SysFreeString(bstrTmp);
	bstrTmp = NULL;

	lnkBaseTool->get_AdditionalLibraryDirectories(&bstrTmp);
	AlignRelPathEx(bstrTmp, bstrBasePath, bstrNewPath, 2);
	lnkNewTool->put_AdditionalLibraryDirectories(bstrTmp);
	SysFreeString(bstrTmp);
	bstrTmp = NULL;

	lnkBaseTool->get_AdditionalDependencies(&bstrTmp);
	AlignRelPathEx(bstrTmp, bstrBasePath, bstrNewPath, 3);
	lnkNewTool->put_AdditionalDependencies(bstrTmp);
	SysFreeString(bstrTmp);
	bstrTmp = NULL;

//	lnkBaseTool->get_OutputFile(&bstrTmp);
//	AlignRelPath(bstrTmp, bstrBasePath, bstrNewPath);
//	lnkNewTool->put_OutputFile(bstrTmp);
//	SysFreeString(bstrTmp);
//	bstrTmp = NULL;
}

void CTestSuiteTool::ClonePrjConfigurations(VCProject* basePrj, VCProject* newPrj)
{
	if(basePrj == NULL || newPrj == NULL)
		return;

	CComPtr<IDispatch> pObj;
	CComQIPtr<IVCCollection> baseManagers;
	CComQIPtr<IVCCollection> newMangers;
	basePrj->get_Configurations(&pObj);
	baseManagers = pObj;

	pObj = NULL;
	newPrj->get_Configurations(&pObj);
	newMangers = pObj;

	pObj = NULL;
	basePrj->get_Object(&pObj);
	CComQIPtr<EnvDTE::Project> _basePrj = pObj;
	CComPtr<EnvDTE::ConfigurationManager> baseCfgMgr;
	_basePrj->get_ConfigurationManager(&baseCfgMgr);
	CComPtr<EnvDTE::Configuration> activeCfg;
	baseCfgMgr->get_ActiveConfiguration(&activeCfg);

	if(baseManagers == NULL || newMangers == NULL)
		return;

	CComPtr<VCConfiguration> cfgBase;
	CComPtr<VCConfiguration> cfgNew;

	BSTR bstrBasePath = NULL;
	BSTR bstrNewPath = NULL;
	basePrj->get_ProjectDirectory(&bstrBasePath);
	newPrj->get_ProjectFile(&bstrNewPath);

	BSTR bstrCfgName = NULL;
	activeCfg->get_ConfigurationName(&bstrCfgName);
	CString sCfgName;
	sCfgName = bstrCfgName;
	SysFreeString(bstrCfgName);
	bstrCfgName = NULL;
	sCfgName.MakeLower();

	GetConfigure(sCfgName, baseManagers, &cfgBase);
	if(sCfgName.Find(L"debug") >= 0)
	{
		GetConfigure(L"debug", newMangers, &cfgNew);
		CopyConfig(cfgBase, bstrBasePath, cfgNew, bstrNewPath);

		cfgNew = NULL;
		cfgBase = NULL;
		GetConfigure(L"release", baseManagers, &cfgBase);
		GetConfigure(L"release", newMangers, &cfgNew);
		CopyConfig(cfgBase, bstrBasePath, cfgNew, bstrNewPath);
	}
	else
	{
		GetConfigure(L"release", newMangers, &cfgNew);
		CopyConfig(cfgBase, bstrBasePath, cfgNew, bstrNewPath);

		cfgNew = NULL;
		cfgBase = NULL;
		GetConfigure(L"debug", baseManagers, &cfgBase);
		GetConfigure(L"debug", newMangers, &cfgNew);
		CopyConfig(cfgBase, bstrBasePath, cfgNew, bstrNewPath);
	}

	SysFreeString(bstrBasePath);
	SysFreeString(bstrNewPath);
}

void CTestSuiteTool::CreateProjectFromTemplate()
{
	if(m_pParent == NULL)
		return;

	CComPtr<EnvDTE::_Solution> solution;
	CComPtr<DTE2> dte2 = m_pParent->m_pDTE;
	HRESULT hr = dte2->get_Solution(&solution);
	if(FAILED(hr) || solution == NULL)
		return;
	CComQIPtr<Solution2> solution2;
	solution2 = solution;

	CComPtr<EnvDTE::SolutionBuild> builder;
	hr = solution2->get_SolutionBuild(&builder);
	if(FAILED(hr) || builder == NULL)
		return;

	//Begin get startup project path
	CString sStartPrjPath = GetStartProject(solution, builder);
	CString sStartPrjDir = ParentDir(sStartPrjPath) + _T("\\");

	//Prompt for user to choose the generated project path
	CCreatePrjDlgImpl impl;
	int ret = impl.DoModal(sStartPrjDir);
	if(ret == IDOK)
	{
		if(!PathIsDirectory(impl.m_sOutputDir))
			CreateDirectory(impl.m_sOutputDir, NULL);
	}

	//Generate the test project
	CComPtr<EnvDTE::Project> newPrj;
	BSTR szDestPath = impl.m_sOutputDir.AllocSysString();
	BSTR szDestName = impl.m_sProjectName.AllocSysString();
	TCHAR szTemplatePath[MAX_PATH] = {0};
	GetModuleFileName(_AtlModule.GetResourceInstance(), szTemplatePath, MAX_PATH);
	PathRemoveFileSpec(szTemplatePath);
	PathAppend(szTemplatePath,  L"GMockTemplate\\GMockTemplate.vsz");
	hr = solution->AddFromTemplate(szTemplatePath, szDestPath, szDestName, VARIANT_FALSE, &newPrj);
	SysFreeString(szDestName);
	SysFreeString(szDestPath);

	if(!SUCCEEDED(hr))
		return;

	newPrj = NULL;
	CComPtr<EnvDTE::Project> basePrj;
	CComPtr<VCProject> baseVcPrj;
	CComPtr<VCProject> newVcPrj;
	GetStartProjectObj(solution, sStartPrjPath, &basePrj, &baseVcPrj);
	GetStartProjectObj(solution, impl.m_sProjectName, &newPrj, &newVcPrj);

	//Clone the project properties from the base project
	ClonePrjConfigurations(baseVcPrj, newVcPrj);

	m_pParent->PrintToOutput(_T("New test project created!"), TRUE);
}

BOOL CTestSuiteTool::EqualBSTR(BSTR s1, BSTR s2)
{
	UINT s1len = ::SysStringByteLen(s1);
	if((s1len == ::SysStringByteLen(s2)) && (::memcmp(s1, s2, s1len) == 0))
	{
		return TRUE;
	}
	return FALSE;
}

CString CTestSuiteTool::ParentDir(const CString& sPath)
{
	int nLastSep = sPath.ReverseFind(_T('\\'));
	if(nLastSep == -1)
		nLastSep = sPath.ReverseFind(_T('/'));

	if(nLastSep == -1)
		return sPath;

	return sPath.Left(nLastSep);
}

CString CTestSuiteTool::MergePath(LPCWSTR sBasePath, LPCWSTR sRelPath)
{
	CString sRet;
	sRet = ParentDir(CString(sBasePath));
	WCHAR* chStart = (WCHAR*)sRelPath;
	while(chStart[0] != _T('\0'))
	{
		if(chStart[0] == _T('\\') || chStart[0] == _T('/'))
		{
			chStart++;
			continue;
		}
		if(chStart[0] != _T('.'))
			break;

		if((chStart[1] == _T('\\') || chStart[1] == _T('/')))
		{
			chStart += 2;
			continue;
		}
		else if(chStart[1] == _T('.'))
		{
			chStart += 2;
			sRet = ParentDir(sRet);
		}
	}
	sRet += _T("\\");
	sRet += CString(chStart);

	return sRet;
}

TCHAR* CTestSuiteTool::RemoveSepFromBegin(TCHAR* sIn)
{
	TCHAR* sPath = sIn;
	while(*sPath != 0 && (*sPath == _T('\\') || *sPath == _T('/')))
		sPath++;
	return sPath;
}

CString CTestSuiteTool::FindFirstName(TCHAR*& sPath)
{
	TCHAR* sRet = sPath;
	sRet = RemoveSepFromBegin(sRet);

	TCHAR* sNext = sRet;
	while(*sNext != 0)
	{
		if((*sNext == _T('\\') || *sNext == _T('/')))
			break;
		sNext++;
	}
	sPath = sNext;
	TCHAR sNameRet[MAX_PATH] = {0};
	memcpy_s(sNameRet, MAX_PATH, sRet, sizeof(TCHAR) * (sNext - sRet));

	return (sNameRet);
}

CString CTestSuiteTool::GetRelPath(LPCWSTR sBasePath, LPCWSTR sDestPath)
{
	TCHAR* pBasePtr = (TCHAR*)sBasePath;
	TCHAR* pDestPtr = (TCHAR*)sDestPath;

	//Remove all the same at the begin.
	while(*pBasePtr != 0 && *pDestPtr != 0)
	{
		TCHAR* pPrevBase = pBasePtr;
		TCHAR* pPrevDest = pDestPtr;
		CString sBaseName;
		sBaseName = FindFirstName(pBasePtr);
		CString sDestName;
		sDestName = FindFirstName(pDestPtr);
		if(sBaseName.CompareNoCase(sDestName) != 0)
		{
			pDestPtr = pPrevDest;
			pBasePtr = pPrevBase;
			break;
		}
	}
	pDestPtr = RemoveSepFromBegin(pDestPtr);

	//Not in the same disk partition
	if(pBasePtr == sBasePath)
		return sDestPath;

	int nCnt = 0;
	while(*pBasePtr != 0)
	{
		FindFirstName(pBasePtr);
		nCnt++;
	}
	CString sRet;
	for(; nCnt > 1; nCnt--)
	{
		sRet += _T("..\\");
	}
	sRet += pDestPtr;
	return sRet;
}

void CTestSuiteTool::InstrumentAssembly(const CString& szToolPath, const CString& sOutPath)
{
	CString sExt = sOutPath.Right(3);
	sExt.MakeLower();

	CString szInstrumentCmd(szToolPath);
	if(sExt == L"dll" || sExt == L"exe")
	{
		szInstrumentCmd += _T("\\vsinstr.exe \"");
		szInstrumentCmd += sOutPath;
		szInstrumentCmd += _T("\" /COVERAGE");
	}

	m_Instrument.Exec(szInstrumentCmd);
	m_Instrument.Join(INFINITE);
}

void CTestSuiteTool::RunSolutionWithCoverage(BOOL bIntsrAll)
{
	if(m_pParent == NULL)
		return;

	if(!m_sOutPath.IsEmpty())
	{
		StopCoverage();
		return;
	}

	CComPtr<EnvDTE::_Solution> solution;
	CComPtr<DTE2> dte2 = m_pParent->m_pDTE;
	HRESULT hr = dte2->get_Solution(&solution);
	if(FAILED(hr) || solution == NULL)
		return;
	CComQIPtr<Solution2> solution2;
	solution2 = solution;

	CComPtr<EnvDTE::SolutionBuild> builder;
	hr = solution2->get_SolutionBuild(&builder);
	if(FAILED(hr) || builder == NULL)
		return;

	CString sStartupPrjPath = GetStartProject(solution, builder);
	CComPtr<EnvDTE::Project> startPrj;
	CComPtr<VCProject> startVcPrj;
	GetStartProjectObj(solution, sStartupPrjPath, &startPrj, &startVcPrj);
	if(startPrj == NULL || startVcPrj == NULL)
		return;
	m_sOutPath = GetProjectOutputPath(startPrj, startVcPrj);

	hr = E_FAIL;
	if(!bIntsrAll)
	{
		m_lstFiles.push_back(m_sOutPath);
		hr = builder->Build(VARIANT_FALSE);
	}
	else
	{
		CComPtr<EnvDTE::BuildDependencies> deps;
		builder->get_BuildDependencies(&deps);
		if(deps != NULL)
		{
			LONG lDepCnt = 0;
			deps->get_Count(&lDepCnt);

			CComPtr<IDispatch> pObj;
			list<CString> lstPath;
			for(int i = 1; i <= lDepCnt; i++)
			{
				CComPtr<EnvDTE::BuildDependency> dep;
				deps->Item(CComVariant(i), &dep);
				CComPtr<EnvDTE::Project> itPrj;
				CComQIPtr<VCProject> itVcPrj;
				dep->get_Project(&itPrj);
				pObj = NULL;
				itPrj->get_Object(&pObj);
				itVcPrj = pObj;

				CString sItPath = GetProjectOutputPath(itPrj, itVcPrj);
				lstPath.push_back(sItPath);
			}
			hr = builder->Build(VARIANT_FALSE);
		}
	}
}

void CTestSuiteTool::BuildDone()
{
	if(m_lstFiles.size() == 0)
		return;

	TCHAR szIDEPath[MAX_PATH] = {0};
	GetModuleFileName(NULL, szIDEPath, MAX_PATH);
	CString szToolPath = MergePath(szIDEPath, _T("..\\..\\Team Tools\\Performance Tools"));

	list<CString>::iterator it = m_lstFiles.begin();
	for(; it != m_lstFiles.end(); it++)
	{
		InstrumentAssembly(szToolPath, *it);
	}
	m_lstFiles.clear();

	if(m_sOutPath.IsEmpty() || !PathFileExists(m_sOutPath))
		return;

	CComPtr<EnvDTE::_Solution> solution;
	CComPtr<DTE2> dte2 = m_pParent->m_pDTE;
	HRESULT hr = dte2->get_Solution(&solution);
	if(FAILED(hr) || solution == NULL)
		return;
	CComQIPtr<Solution2> solution2;
	solution2 = solution;

	CComPtr<EnvDTE::SolutionBuild> builder;
	hr = solution2->get_SolutionBuild(&builder);
	if(FAILED(hr) || builder == NULL)
		return;

	CString szPerformMon(szToolPath);
	szPerformMon += L"\\VSPerfMon.exe /COVERAGE /OUTPUT:";
	szPerformMon += m_sOutPath;
	szPerformMon += L".coverage";
	m_PerformMon.Exec(szPerformMon);

	builder->Run();
}

void CTestSuiteTool::StopCoverage()
{
	if(m_sOutPath.IsEmpty())
		return;

	TCHAR szIDEPath[MAX_PATH] = {0};
	GetModuleFileName(NULL, szIDEPath, MAX_PATH);
	CString szToolPath = MergePath(szIDEPath, _T("..\\..\\Team Tools\\Performance Tools"));

	CString szStop(szToolPath);
	szStop += L"\\VSPerfCmd.exe /SHUTDOWN";
	m_PerformStop.Exec(szStop);
	m_PerformStop.Join(INFINITE);
	m_PerformMon.Join(INFINITE);

	RestoreChangedProject();

	CString sCoveragePath = m_sOutPath;
	CString sHtmlPath = m_sOutPath;
	CString sPdbPath;// = m_sOutPath;
//	sPdbPath.Left(sPdbPath.GetLength() - 3);
//	sPdbPath += L"pdb";
	sCoveragePath += L".coverage";
	sHtmlPath += L".html";
	BSTR bstrPath = sCoveragePath.AllocSysString();
	BSTR bstrExePath = m_sOutPath.AllocSysString();
	BSTR bstrHtmlPath = sHtmlPath.AllocSysString();
	BSTR bstrPdbPath = sPdbPath.AllocSysString();
	CComPtr<EnvDTE::Window> pWin;
	m_pParent->m_pDTE->OpenFile(NULL, bstrPath, &pWin);

	CovAnalyze::ICovInfoPtr pCom(__uuidof(CovAnalyze::CCovInfo));
	if(pCom != NULL)
		pCom->GenerageReport(bstrPdbPath, bstrExePath, bstrPath, bstrHtmlPath);

	SysFreeString(bstrPath);
	SysFreeString(bstrPdbPath);
	SysFreeString(bstrExePath);
	SysFreeString(bstrHtmlPath);
	m_sOutPath.Empty();
}

CString CTestSuiteTool::GetProjectOutputPath(EnvDTE::Project* startPrj, VCProject* startVCPrj)
{
	CString sRet;

	CComPtr<EnvDTE::ConfigurationManager> cfgMgr;
	startPrj->get_ConfigurationManager(&cfgMgr);
	CComPtr<EnvDTE::Configuration> activeCfg;
	cfgMgr->get_ActiveConfiguration(&activeCfg);

	if(activeCfg == NULL)
		return sRet;

	BSTR bstrTmp = NULL;
	CComPtr<EnvDTE::Properties> activeProps;
	activeCfg->get_Properties(&activeProps);
	CComPtr<EnvDTE::Property> prop;
	activeProps->Item(CComVariant(L"OutputPath"), &prop);
	CComVariant varOutputPath;
	prop->get_Value(&varOutputPath);
	sRet = varOutputPath.bstrVal;

	CComPtr<EnvDTE::OutputGroups> outGroups;
	activeCfg->get_OutputGroups(&outGroups);
	CComPtr<EnvDTE::OutputGroup> outGroup;
	outGroups->Item(CComVariant(1), &outGroup);
	CComVariant pNames;
	outGroup->get_FileNames(&pNames);
	if(pNames.vt == (VT_ARRAY | VT_VARIANT))
	{
		VARIANT vTmp;
		CComSafeArray<VARIANT> safeArr(pNames.parray);
		if(safeArr.GetCount() > 0)
		{
			vTmp = safeArr.GetAt(0);
			if(vTmp.vt == VT_BSTR)
			{
				CString sOutputName = vTmp.bstrVal;
				sRet += sOutputName;
			}
		}
	}

	//Change the project profile to TRUE.
	BSTR bstrCfgName = NULL;
	activeCfg->get_ConfigurationName(&bstrCfgName);
	CString sCfgName;
	sCfgName = bstrCfgName;
	SysFreeString(bstrCfgName);
	bstrCfgName = NULL;
	sCfgName.MakeLower();

	CComQIPtr<IVCCollection> curManagers;
	CComPtr<IDispatch> pObj;
	startVCPrj->get_Configurations(&pObj);
	curManagers = pObj;
	CComPtr<VCConfiguration> vcCfg;
	GetConfigure(sCfgName, curManagers, &vcCfg);

	CComQIPtr<VCLinkerTool> lnkTool;
	vcCfg->get_Tools(&pObj);
	CComQIPtr<IVCCollection> pTools;
	pTools = pObj;
	pObj = NULL;
	pTools->Item(CComVariant("VCLinkerTool"), &pObj);
	lnkTool = pObj;

	if(lnkTool == NULL)
		return sRet;

	VARIANT_BOOL varBool;
	lnkTool->get_Profile(&varBool);
	if(varBool == VARIANT_FALSE)
	{
		lnkTool->put_Profile(VARIANT_TRUE);
		VCLinkerTool* pTmp = lnkTool;
		pTmp->AddRef();
		m_changedList.push_back(pTmp);
	}

	return sRet;
}

void CTestSuiteTool::RestoreChangedProject()
{
	list<VCLinkerTool*>::iterator it = m_changedList.begin();
	for(; it != m_changedList.end(); it++)
	{
		VCLinkerTool* lnkTool = *it;
		if(lnkTool != NULL)
		{
			lnkTool->put_Profile(VARIANT_FALSE);
			lnkTool->Release();
		}
	}
	m_changedList.clear();
}

void CTestSuiteTool::OutputLogString(LPCTSTR lpszStr)
{
	if(m_pParent)
		m_pParent->PrintToOutput(lpszStr);
}

CString CTestSuiteTool::GetStartProject(EnvDTE::_Solution* solution, EnvDTE::SolutionBuild* builder)
{
	//Begin get startup project path
	CComVariant prjCurrent; 
	HRESULT hr = builder->get_StartupProjects(&prjCurrent);
	BSTR sPrjPath = NULL;
	if(prjCurrent.vt == (VT_ARRAY | VT_VARIANT))
	{
		VARIANT vTmp;
		CComSafeArray<VARIANT> safeArr(prjCurrent.parray);
		if(safeArr.GetCount() > 0)
		{
			vTmp = safeArr.GetAt(0);
			if(vTmp.vt == VT_BSTR)
				sPrjPath = SysAllocString(vTmp.bstrVal);
		}
	}
	CString sRet(sPrjPath);

	BSTR szSlnPath = NULL;
	solution->get_FullName(&szSlnPath);
	sRet = MergePath(szSlnPath, sPrjPath);

	SysFreeString(szSlnPath);
	SysFreeString(sPrjPath);

	return sRet;
}

void CTestSuiteTool::GetStartProjectObj(EnvDTE::_Solution* sln, CString szStartName, EnvDTE::Project** startPrj, VCProject** startVCPrj)
{
	if(sln == NULL)
		return;

	CComPtr<EnvDTE::Projects> allPrjs;
	sln->get_Projects(&allPrjs);
	if(allPrjs == NULL)
		return;

	*startPrj = NULL;
	*startVCPrj = NULL;
	LONG lCnt = 0;
	allPrjs->get_Count(&lCnt);

	for(int i = 1; i <= lCnt; i++)
	{
		CComPtr<EnvDTE::Project> tmpPrj;
		allPrjs->Item(CComVariant(i), &tmpPrj);
		BSTR bstrTmpName = NULL;
		tmpPrj->get_FullName(&bstrTmpName);
		CString sTmpPath(bstrTmpName);
		SysFreeString(bstrTmpName);

		bstrTmpName = NULL;
		tmpPrj->get_Name(&bstrTmpName);
		CString sTmpName(bstrTmpName);
		SysFreeString(bstrTmpName);

		if(szStartName == sTmpPath || sTmpName == szStartName)
		{
			*startPrj = tmpPrj;
			(*startPrj)->AddRef();
			CComPtr<IDispatch> pObj;
			CComQIPtr<VCProject> tmpVcPrj;
			tmpPrj->get_Object(&pObj);
			tmpVcPrj = pObj;
			*startVCPrj = tmpVcPrj;
			(*startVCPrj)->AddRef();
			break;
		}
	}
}
